package com.cskaoyan.javase._2polymorphic._2advantage;

/**
 * 案例:
 * 科学家要收集动物的叫声去研究
 * 先要收集猫，狗两种动物的叫声研究。
 * 随后又扩展到其它动物，最后又需要研究人类。
 *
 * 通过一个形参类型是父类类型的方法,允许传入不同的子类对象
 * 然后调用同名子类重写的成员方法,会根据传入对象的类型不同,体现不同的行为
 * 这就是多态现象在方法中的应用,也是开发中使用多态最常见的场景之一.
 *
 * 从这个案例，我们其实就可以大致总结多态的优点了：
 *      1.要实现多态必须要继承，而继承提高了代码复用率，提升了程序的可维护性。（继承保证）
 *      2.有了多态后，用父类引用指向不同子类对象，只需要调用同名方法，就能自动根据不同子类对象，得出不同的行为。这大幅度简化了代码，提升了程序的扩展性。（多态保证）
 *
 *      多态的缺点:
 *      多态必须使用父类引用指向不同子类对象
 *      所以父类引用会限制子类对象的访问范围
 *      父类引用无法访问子类独有成员
 *
 * 怎么解决这样一个缺点呢?
 *      父类引用限制了访问范围
 *      需要将它转换成子类引用
 *      父类引用 --> 子类引用
 *      向下转型,也就是引用数据类型的强制类型转换
 *
 * @since 11:22
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // collectCatVoice(new Cat());
        collectAnimalVoice(new Dog());
        collectAnimalVoice(new Cat());
        collectAnimalVoice(new Pig());
        collectAnimalVoice(new Person());
    }

    // public static void collectCatVoice(Cat c) {
    //     // 抓一只猫过来,让它叫
    //     c.shout();
    // }
    public static void collectAnimalVoice(Animal a) {
        // 人类对象传入后,需要先调用加钱方法,然后才能shout
        // 使用instanceof做判断,只有当传入Person对象时,才进行强转
        if (a instanceof Person) {
            // 把Animal引用 --> Person引用
            Person p = (Person) a;
            p.addMoney();
        }
        // 抓一只动物过来,让它叫
        a.shout();
    }
}

class Animal {
    void shout() {
        System.out.println("动物叫!");
    }
}

class Cat extends Animal {
    @Override
    void shout() {
        System.out.println("喵喵喵!");
    }
}

class Dog extends Animal {
    @Override
    void shout() {
        System.out.println("汪汪汪~");
    }
}

class Pig extends Animal {
    @Override
    void shout() {
        System.out.println("小猪佩奇身上纹,你我都是社会人");
    }
}

class Person extends Animal {

    // 人有自身独特的行为,让它叫,得加钱
    public void addMoney() {
        System.out.println("我是独立的,有尊严的人,让我叫不行,得加钱!");
    }

    @Override
    void shout() {
        System.out.println("嘤嘤嘤~");
    }
}